using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using UnityEngine;

namespace BitMango.Diagnostics
{
    internal static class TraceListener
    {
        public static void AddDefaultTable(string key, string val)
        {
            if (TraceListener.defaultTable != null)
            {
                TraceListener.defaultTable[key] = val;
            }
            else
            {
                UnityEngine.Debug.LogError("AddDefaultTable defaultTable is null : " + key + "/" + val);
            }
        }

        public static void Init(Hashtable param)
        {
            if (TraceListener.defaultTable != null)
            {
                return;
            }
            TraceListener.defaultTable = new Hashtable
            {
                {
                    "startup",
                    DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff")
                },
                {
                    "session",
                    Guid.NewGuid().ToString()
                }
            };
            if (param != null)
            {
                IDictionaryEnumerator enumerator = param.GetEnumerator();
                try
                {
                    while (enumerator.MoveNext())
                    {
                        object obj = enumerator.Current;
                        DictionaryEntry dictionaryEntry = (DictionaryEntry)obj;
                        TraceListener.defaultTable[dictionaryEntry.Key] = dictionaryEntry.Value;
                    }
                }
                finally
                {
                    IDisposable disposable;
                    if ((disposable = (enumerator as IDisposable)) != null)
                    {
                        disposable.Dispose();
                    }
                }
            }
            if (Platform.IsEU() && !Platform.IsTOSAgreed)
            {
                return;
            }
            AppDomain currentDomain = AppDomain.CurrentDomain;
            if (TraceListener._003C_003Ef__mg_0024cache0 == null)
            {
                TraceListener._003C_003Ef__mg_0024cache0 = new UnhandledExceptionEventHandler(TraceListener.OnUnresolvedExceptionHandler);
            }
            currentDomain.UnhandledException += TraceListener._003C_003Ef__mg_0024cache0;
            if (TraceListener._003C_003Ef__mg_0024cache1 == null)
            {
                TraceListener._003C_003Ef__mg_0024cache1 = new Application.LogCallback(TraceListener.OnLogCallbackHandler);
            }
            Debugger.Application.RegisterLogCallback(TraceListener._003C_003Ef__mg_0024cache1, true);
        }

        private static void FilterPolicyRemove()
        {
            foreach (TraceListener.Filter filter in TraceListener.filters)
            {
                filter.Remove(TraceListener.queueMsg);
            }
        }

        private static bool FilterPolicyAdd(TraceListener.EventLog item)
        {
            foreach (TraceListener.Filter filter in TraceListener.filters)
            {
                if (filter.IsFiltered(TraceListener.queueMsg, item))
                {
                    return false;
                }
            }
            TraceListener.queueMsg.Add(item);
            return true;
        }

        private static void OnLogCallbackHandler(string condition, string stacktrace, LogType type)
        {
            if (type == LogType.Log)
            {
                return;
            }
            if (type == LogType.Warning)
            {
                return;
            }
            if (string.IsNullOrEmpty(stacktrace))
            {
                StackTrace stackTrace = new StackTrace();
                stacktrace = stackTrace.ToString().Replace("   at ", string.Empty);
            }
            if (type == LogType.Exception)
            {
                int num = condition.IndexOf(Debugger.assertPrefix);
                if (num >= 0)
                {
                    condition = LogType.Assert.ToString() + ": " + condition.Substring(num + Debugger.assertPrefix.Length);
                    type = LogType.Assert;
                }
            }
            TraceListener.ProcessCallbackEventLog(condition, stacktrace, type.ToString(), type);
        }

        private static void OnUnresolvedExceptionHandler(object sender, UnhandledExceptionEventArgs args)
        {
            if (args == null)
            {
                return;
            }
            if (args.ExceptionObject == null)
            {
                return;
            }
            try
            {
                Type type = args.ExceptionObject.GetType();
                if (type == typeof(Exception))
                {
                    Exception ex = (Exception)args.ExceptionObject;
                    string message = ex.Message;
                    string stacktrace = ex.ToString();
                    if (args.IsTerminating)
                    {
                        TraceListener.ProcessCallbackEventLog(message, stacktrace, "UnresolvedTerminate", LogType.Exception);
                    }
                    else
                    {
                        TraceListener.ProcessCallbackEventLog(message, stacktrace, "UnresolvedException", LogType.Exception);
                    }
                }
            }
            catch
            {
                UnityEngine.Debug.Log("Debuger: Failed to resolve exception");
            }
        }

        private static void ProcessCallbackEventLog(string condition, string stacktrace, string typeString, LogType type = LogType.Exception)
        {
            if (type == LogType.Error)
            {
                TraceListener.ReportCrashlyticsNonFatal(condition, stacktrace);
            }
            else if (type == LogType.Assert)
            {
                char[] delim = new char[]
                {
                    '\n'
                };
                string[] messageParts = TraceListener.GetMessageParts(condition, delim);
                TraceListener.ReportCrashlyticsNonFatal(messageParts[0], messageParts[1]);
            }
            else if (type == LogType.Exception)
            {
                TraceListener.ReportCrashlyticsNonFatal(condition, stacktrace);
            }
            else
            {
                TraceListener.ReportCrashlyticsNonFatal(condition, stacktrace);
            }
        }

        private static void ReportCrashlyticsNonFatal(string message, string stackTraceString)
        {
            char[] delim = new char[]
            {
                ':'
            };
            string[] messageParts = TraceListener.GetMessageParts(message, delim);
            messageParts[0] = messageParts[1].Replace(" ", "_");
            messageParts[1] = messageParts[1].Replace(" ", "_");
            string str = string.Format("{0}.{1}()", messageParts[1], messageParts[0]) + Environment.NewLine;
        }

        private static string[] GetMessageParts(string message, char[] delim)
        {
            string[] array = message.Split(delim, 2, StringSplitOptions.None);
            for (int i = 0; i < array.Length; i++)
            {
                array[i] = array[i].Trim();
            }
            if (array.Length == 2)
            {
                return array;
            }
            return new string[]
            {
                "Exception",
                message
            };
        }

        private static readonly string KEY_LAST_EventLog = "debuger_EventLog";

        public static bool enableLocalLog = false;

        private static TraceListener.Filter[] filters = new TraceListener.Filter[]
        {
            new TraceListener.Filter(5f, 2, TraceListener.FilterType.Duplicate),
            new TraceListener.Filter(5f, 5, TraceListener.FilterType.Duration),
            new TraceListener.Filter(20f, 10, TraceListener.FilterType.Duration),
            new TraceListener.Filter(80f, 15, TraceListener.FilterType.Duration),
            new TraceListener.Filter(320f, 20, TraceListener.FilterType.Duration),
            new TraceListener.Filter(320f, 0, TraceListener.FilterType.Duration)
        };

        private static List<TraceListener.EventLog> queueMsg = new List<TraceListener.EventLog>();

        private static Hashtable defaultTable = null;

        [CompilerGenerated]
        private static UnhandledExceptionEventHandler _003C_003Ef__mg_0024cache0;

        [CompilerGenerated]
        private static Application.LogCallback _003C_003Ef__mg_0024cache1;

        private class EventLog
        {
            public EventLog(string condition, string stacktrace, string type)
            {
                this.tick = Time.realtimeSinceStartup;
                this.condition = condition;
                this.stacktrace = stacktrace;
                this.type = type;
            }

            public bool Equals(TraceListener.EventLog msg)
            {
                return !(this.condition != msg.condition) && !(this.stacktrace != msg.stacktrace) && !(this.type != msg.type);
            }

            public override string ToString()
            {
                return string.Format("{0}:{1}\r\n{2}\r\n{3}", new object[]
                {
                    this.tick,
                    this.type,
                    this.condition,
                    this.stacktrace
                });
            }

            public readonly float tick;

            public string condition;

            public string stacktrace;

            public string type;
        }

        private enum FilterType
        {
            Duration,
            Duplicate
        }

        private class Filter
        {
            public Filter(float time, int count, TraceListener.FilterType type)
            {
                this.time = time;
                this.count = count;
                this.type = type;
            }

            public void Remove(List<TraceListener.EventLog> queueMsg)
            {
                if (this.type != TraceListener.FilterType.Duration)
                {
                    return;
                }
                float realtimeSinceStartup = Time.realtimeSinceStartup;
                int num = 0;
                for (int i = queueMsg.Count - 1; i >= 0; i--)
                {
                    TraceListener.EventLog eventLog = queueMsg[i];
                    if (this.count == 0)
                    {
                        if (realtimeSinceStartup - eventLog.tick > this.time)
                        {
                            queueMsg.RemoveAt(i);
                        }
                    }
                    else if (realtimeSinceStartup - eventLog.tick <= this.time)
                    {
                        num++;
                        if (num > this.count)
                        {
                            queueMsg.RemoveAt(i);
                        }
                    }
                }
            }

            public bool IsFiltered(List<TraceListener.EventLog> queueMsg, TraceListener.EventLog item)
            {
                if (this.count == 0)
                {
                    return false;
                }
                float tick = Time.realtimeSinceStartup;
                int num = queueMsg.Count((TraceListener.EventLog msg) => tick - msg.tick <= this.time && (this.type != TraceListener.FilterType.Duplicate || item.Equals(msg)));
                return num >= this.count;
            }

            public TraceListener.FilterType type;

            public float time;

            public int count;
        }
    }
}
